
using System;
using System.Threading;
using Microsoft.Xna.Framework.Graphics;

namespace Lucy.Integration.Wpf
{
    class GraphicsDeviceService : IGraphicsDeviceService
    {
        private static readonly GraphicsDeviceService SingletonInstance = new GraphicsDeviceService();
        private static int _referenceCount;

        private GraphicsDevice _graphicsDevice;
        private PresentationParameters _parameters;

        public GraphicsDevice GraphicsDevice
        {
            get { return _graphicsDevice; }
        }

        public event EventHandler<EventArgs> DeviceCreated;
        public event EventHandler<EventArgs> DeviceDisposing;
        public event EventHandler<EventArgs> DeviceReset;
        public event EventHandler<EventArgs> DeviceResetting;

        private GraphicsDeviceService() { }

        private void CreateDevice(IntPtr windowHandle, int width, int height)
        {
            _parameters = new PresentationParameters
            {
                BackBufferWidth = Math.Max(width, 1),
                BackBufferHeight = Math.Max(height, 1),
                BackBufferFormat = SurfaceFormat.Color,
                DepthStencilFormat = DepthFormat.Depth24,
                DeviceWindowHandle = windowHandle,
                PresentationInterval = PresentInterval.Immediate,
                IsFullScreen = false
            };
            
            _graphicsDevice = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, GraphicsProfile.Reach, _parameters);

            if (DeviceCreated != null)
                DeviceCreated(this, EventArgs.Empty);
        }

        public static GraphicsDeviceService AddRef(IntPtr windowHandle, int width, int height)
        {
            if (Interlocked.Increment(ref _referenceCount) == 1)
            {
                SingletonInstance.CreateDevice(windowHandle, width, height);
            }

            return SingletonInstance;
        }


        public void Release(bool disposing)
        {
            if (Interlocked.Decrement(ref _referenceCount) == 0)
            {
                if (disposing)
                {
                    if (DeviceDisposing != null)
                        DeviceDisposing(this, EventArgs.Empty);

                    _graphicsDevice.Dispose();
                }

                _graphicsDevice = null;
            }
        }

        
        public void ResetDevice(int width, int height)
        {
            if (DeviceResetting != null)
                DeviceResetting(this, EventArgs.Empty);

            _parameters.BackBufferWidth = Math.Max(_parameters.BackBufferWidth, width);
            _parameters.BackBufferHeight = Math.Max(_parameters.BackBufferHeight, height);

            _graphicsDevice.Reset(_parameters);

            if (DeviceReset != null)
                DeviceReset(this, EventArgs.Empty);
        }
    }
}
